﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace SkyBase
{
    public enum direction { RIGHT, BOTTOMRIGHT, BOTTOM, BOTTOMLEFT, LEFT, TOPLEFT, TOP, TOPRIGHT, NONE }
    class GameObject
    {

        private String name; //Required for easy access in storage.
        private Vector2 location; //Location corresponds to the top lefthand corner of the object. If the Sprite is round this point is off of the sprite itself.
        private Texture2D sprite;
        private bool collidable; //Other objects will run into this object. If an object is ONLY collidable, it will not be checked for collision every update
        protected Vector2 velocity; //The current speed of the object. Every update this will be added to the location.
        public double rotation;
        private int health = -1; //If changed to positive the object is killable
        protected static World world;
        public bool showingUp { get; set; } //If true, the object is drawn to the screen. If false, the object is not drawn.
        public bool drawBounds { get; set; }
        public bool checkForCollision = false; //This object can collide into others. It will be checked for collision every update.
        public bool ghost = false; //Can this object pass through other objects and vice versa?
        public float priority; //Priority for drawing. 0.5 is the default. 0-0.5 front, 0.5-2 back.
        public int duplicateNum { get; set; } //Are we a duplicate of anything in the world? This keeps track of that.
        public Color color;
        public Rectangle bounds;

        //The direction we're facing
        public direction direction {get; set;}
        //Our current frame in our animation
        private int currentFrame = 0;

        private Dictionary<direction, List<Texture2D>> animationMap;

        public GameObject(String nameIn, Vector2 locationIn, Texture2D spriteIn, bool collidableIn, World worldIn, float priority = 0.5f)
        {
            this.priority = priority;
            this.color = Color.White;
            name = nameIn;
            location = locationIn;
            world = worldIn;
            animationMap = new Dictionary<direction, List<Texture2D>>();
            this.direction = direction.BOTTOM;

            //If we don't have a texture, create a rectangle!
            if (spriteIn != null)
                sprite = spriteIn;
            else
                sprite = world.GetEngine().Content.Load<Texture2D>("Textures/testplayer");
            
            collidable = collidableIn;
            showingUp = true;
            drawBounds = false;
            duplicateNum = 0;
            //bounds = new Rectangle((int)location.X, (int)location.Y, sprite.Width, sprite.Height);
        }

        public GameObject(String nameIn, Vector2 locationIn, Texture2D spriteIn, bool collidableIn, World worldIn, int healthIn)
        {
            name = nameIn;
            location = locationIn;
            world = worldIn;

            //If we don't have a texture, create a rectangle!
            if (spriteIn != null)
                sprite = spriteIn;
            else
                sprite = world.GetEngine().Content.Load<Texture2D>("Textures/testplayer");

            collidable = collidableIn;
            health = healthIn;
            showingUp = true;
            //bounds = new Rectangle((int)location.X, (int)location.Y, sprite.Width, sprite.Height);
        }

        

        public Texture2D Sprite
        {
            get { return this.sprite; }
            set { sprite = value; }
            //set { sprite = value; bounds = new Rectangle((int)location.X, (int)location.Y, sprite.Width, sprite.Height);}
        }

        public String Name
        {
            get { return this.name; }
            set { name = value; }
        }

        public Vector2 Location
        {
            get { return this.location; }
            set { this.location = value; }
        }

        public float VX
        {
            get { return velocity.X; }
            set { velocity.X = value; }
        }

        public float VY
        {
            get { return velocity.Y; }
            set { velocity.Y = value; }
        }

        public World World
        {
            get { return world; }
            set { world = World; }
        }


        /// <summary>
        /// What to do on Collision.
        /// </summary>
        /// <param name="collidee">The object that was collided with.</param>
        public virtual void onCollision(GameObject collidee)
        {

        }


        /// <summary>
        /// Animate the player using the current direction and frame.
        /// (this assumes all maps are "synced" as far as frames are concerned)
        /// </summary>
        public void updateTextures(string name)
        {
            if (velocity.X != 0 || velocity.Y != 0)
            {
                if (currentFrame < Storage.getMap(name, this.direction).Count - 1)
                    currentFrame++;
                else
                    currentFrame = 0;
                this.sprite = Storage.getMap(name, this.direction)[currentFrame];
            }
            else
            {
                this.sprite = Storage.getMap(name, this.direction)[0];
            }
            
        }

        public virtual void Update()

        {
            
        }

        public virtual void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(Sprite, Bounds,
                            null, color, (float)GetRotation(),
                            new Vector2(0, 0), SpriteEffects.None, priority);
        }

        /// <summary>
        /// Adds the current velocity values to the location.
        /// </summary>
        /// <param name="x">Additional x axis value to add</param>
        /// <param name="y">Additional y axis value to add</param>
        public virtual void updateLocation(float x=0, float y=0)
        {
            this.location += velocity + new Vector2(x, y);
        }

        public double GetRotation()
        {
            return rotation;
        }

        public void SetRotation(double intIn)
        {
            rotation = intIn;
        }

        /// <summary>
        /// Get the object's bounding box.
        /// </summary>
        public virtual Rectangle Bounds
        {
            get { return new Rectangle((int)location.X, (int)location.Y, sprite.Width, sprite.Height); }
            //get {return bounds;}
            //set { bounds = value; }
        }

        /// <summary>
        /// Get the object's bounding box 1 unit of time in the future.
        /// </summary>
        public Rectangle ProjectedBounds
        {
            get 
            {
                return new Rectangle((int)location.X +(int)velocity.X, (int)location.Y + (int)velocity.Y, sprite.Width, sprite.Height); 
            }
        }


        public bool isCollidable
        {
            get { return collidable; }
        }
    }
}
